/*
 * Copyright (c) 2011 Ayan Dave http://www.linkedin.com/in/daveayan
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
 * associated documentation files (the "Software"), to deal in the Software without restriction, including 
 * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the 
 * following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or substantial 
 * portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package testrj.persister;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;

import testrj.domain.DomainObject;
import testrj.domain.MethodToTest;
import testrj.domain.SerializedData;
import testrj.domain.TestCase;
import testrj.domain.TestrjConfig;
import testrj.domain.TestrjUtils;

public class LocalFileSystemPersister implements Persister {
	static int filecount = 1;
	static FilenameFilter TESTS_FILTER = new TestFilesFilter();
	static FilenameFilter DATA_FILTER = new DataFilesFilter();
	
	public void persistTest(MethodToTest methodToTest) {
		String packageName = methodToTest.getObjectForObjectUnderTest().getClass().getPackage().getName();
		String referenceName = packageName.replace(".", "/") + "/" + methodToTest.getObjectForObjectUnderTest().getClass().getSimpleName() + "Test";
		methodToTest.getAllTestCases().add(methodToTest.currentTestCase());
		String data = TestrjConfig.test_serializer.serialize(methodToTest).toString();
		persistTest(referenceName, data);
	}

	public String persistData(DomainObject domainObject) {
		String reference = null;
		if (domainObject.isNull() || domainObject.isVoid() || domainObject.isSymbolicPrimitive()) {
			reference = domainObject.getSerializedData().toString();
		} else {
			reference = persistData(getDataReferenceName(domainObject), domainObject.getSerializedData());
		}
		return reference;
	}

	public List<Object[]> getAutoRunTestDataSet() {
		List<Object[]> dataset = new ArrayList<Object[]>();
		File dir = new File(TestrjConfig.testsFolderLocation);
		String[] children = dir.list(TESTS_FILTER);
		if (children != null) {
			for (int i = 0; i < children.length; i++) {
				File testDir = new File(TestrjConfig.testsFolderLocation + "/" + children[i]);
				String[] testFiles = testDir.list();
				if (testFiles != null) {
					for (String testFile : testDir.list()) {
						String fullFileName = TestrjConfig.testsFolderLocation + children[i] + "/" + testFile;
						MethodToTest methodToTest = getSingleTestDataSet(new File(fullFileName));
						for (TestCase testCase : methodToTest.getAllTestCases()) {
							if (testCase.getRunAutoTest() == true) {
								dataset.add(new Object[] { fullFileName, testCase.getId() });
							}
						}
					}
				}
			}
		}
		return dataset;
	}

	public MethodToTest getSingleTestDataSet(Object forDataSetReference) {
		File fileOnDisk = new File(testFileLocationAndName(forDataSetReference.toString()));
		return getSingleTestDataSet(fileOnDisk);
	}

	public Object getSingleDataSet(Object forDataSetReference, boolean prepareName) {
		String referenceName = forDataSetReference.toString();
		if (prepareName) {
			referenceName = TestrjConfig.testsFolderLocation + forDataSetReference.toString();
		}
		if (referenceName.startsWith(TestrjConfig.testsFolderLocation)) {
			File fileOnDisk = new File(referenceName);
			return getSingleDataSet(fileOnDisk);
		}
		return referenceName;
	}

	private void persistTest(String referenceName, String data) {
		try {
			FileUtils.writeStringToFile(new File(testFileLocationAndName(referenceName)), data);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private Object getSingleDataSet(File fileOnDisk) {
		if (fileOnDisk.exists()) {
			try {
				String fileContents = FileUtils.readFileToString(fileOnDisk);
				Object object = (Object) TestrjConfig.data_serializer.deSerialize(new SerializedData(fileContents));
				return object;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return null;
	}

	private MethodToTest getSingleTestDataSet(File fileOnDisk) {
		if (fileOnDisk.exists()) {
			try {
				String fileContents = FileUtils.readFileToString(fileOnDisk);
				MethodToTest methodToTest = (MethodToTest) TestrjConfig.data_serializer.deSerialize(new SerializedData(fileContents));
				return methodToTest;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return null;
	}

	private String persistData(String referenceName, SerializedData data) {
		try {
			String fileName = getDataHomeLocation(referenceName);
			FileUtils.writeStringToFile(new File(fileName), data.toString());
			return fileName;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private String testFileLocationAndName(String referenceName) {
		return TestrjConfig.testsFolderLocation + referenceName + ".java";
	}

	public String getDataHomeLocation(String referenceName) {
		return TestrjConfig.testsFolderLocation + dataFileName(referenceName);
	}

	private String dataFileName(String referenceName) {
		return "DATA-" + referenceName + "/" + filecount++ + ".txt";
	}

	// private String[] getAllExistingDataSetsForReference(final String
	// referenceName) {
	// File dir = new File(TestrjConfig.testsFolderLocation);
	// FilenameFilter filter = new FilenameFilter() {
	// public boolean accept(File dir, String name) {
	// if(name.startsWith(dataFileName(referenceName)))
	// return true;
	// return false;
	// }
	// };
	// String[] children = dir.list(filter);
	// if(children == null)
	// children = new String[] {};
	// return children;
	// }

	public String getDataReferenceName(DomainObject domainObject) {
		return domainObject.className();
	}

	public String consolidateDataAndTests() {
		String[] allTestFileNames = new File(TestrjConfig.testsFolderLocation).list(TESTS_FILTER);
		for (String testFileName : allTestFileNames) {
			MethodToTest mtt = getSingleTestDataSet(TestrjConfig.testsFolderLocation + testFileName);
			for (TestCase testcase : mtt.getAllTestCases()) {

			}
		}
		return null;
	}

	public LocalFileSystemPersister() {
		countDataFiles();
	}

	private void countDataFiles() {
		String[] files = new File(TestrjConfig.testsFolderLocation).list(DATA_FILTER);
		if (files != null) {
			filecount = new File(TestrjConfig.testsFolderLocation).list(DATA_FILTER).length + 1;
		}
	}
}

class TestFilesFilter implements FilenameFilter {
	public boolean accept(File dir, String name) {
		if (name.startsWith("TEST-"))
			return true;
		return false;
	}
}

class DataFilesFilter implements FilenameFilter {
	public boolean accept(File dir, String name) {
		if (name.startsWith("DATA-"))
			return true;
		return false;
	}
}